home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / news / readers / skim-0.8 / skim-0 / skim-0.8.4 / xskim < prev   
Text File  |  1996-02-18  |  35KB  |  1,215 lines

  1. #!/bin/bash
  2. #
  3. # First a bit of trickery to use bash to find wish in $PATH.
  4. #\
  5. E="\nError: xskim requires the Tcl/Tk package.\n\n\
  6. The 'wish' executable of Tcl/Tk appears to be missing. Please check if Tcl/Tk\n\
  7. is properly installed and check if the bin directory with the 'wish'\n\
  8. executable is in your PATH. Typically, wish resides in /usr/bin or\n\
  9. /usr/local/bin.\n\n\
  10. This version of skim is known to work with Tcl 7.4 and Tk 4.0.\n\n\
  11. Your current PATH is: $PATH\n"; \
  12. if [ -z $(type -path wish) ]; \
  13. then \
  14.     echo -e "$E"; \
  15.     exit 1; \
  16. else \
  17.     exec wish $0 "$@"; \
  18. fi \
  19.  
  20. # NAME
  21. #    xskim
  22. # DESCRIPTION
  23. #    A graphical interface for skim, based on TclX/Tk.
  24. # COPYRIGHT
  25. #    xskim - Graphical interface for skim.
  26. #
  27. #    xskim is based on skim.tcl, which is Copyright (C) 1996 Christoph Neerfeld.
  28. #    skim.tcl is in the skim_tcl package which was uploaded to sunsite.unc.edu
  29. #    as an optional graphical interface for skim version 0.1. From skim version
  30. #    0.4 onwards skim.tcl is renamed to xskim and is integrated in the Skim 
  31. #    package. Changes to xskim are documented in the README file.
  32. #
  33. #    Skim - Off-line news reading package optimized for slow lines.
  34. #    Copyright (C) 1996  Rene W.J. Pijlman
  35. #
  36. #    This program is free software; you can redistribute it and/or modify
  37. #    it under the terms of the GNU General Public License as published by
  38. #    the Free Software Foundation; either version 2 of the License, or
  39. #    (at your option) any later version.
  40. #
  41. #    This program is distributed in the hope that it will be useful,
  42. #    but WITHOUT ANY WARRANTY; without even the implied warranty of
  43. #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  44. #    GNU General Public License for more details.
  45. #
  46. #    You should have received a copy of the GNU General Public License
  47. #    along with this program; if not, write to the Free Software
  48. #    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  49. # VERSION
  50. #    Skim version 0.8.4
  51. #    $Header: /home/rene/sys/CVS_MasterSourceRepository/skim/xskim,v 1.8 1996/02/17 22:47:37 rene Exp $
  52.  
  53. # Just a dummy call to skim to create the directory structure if necessary.
  54. exec skim version >/dev/null
  55.  
  56. # Use the default value when SKIMDIR is not set.
  57. if { [lsearch [array names env] SKIMDIR] >= 0 } {
  58.     set skimhome $env(SKIMDIR)
  59. } else {
  60.     set skimhome [glob ~/Skim]
  61. }
  62.  
  63. set fixed_font "7x14"
  64.  
  65. set text_font $fixed_font
  66. set edit_font $fixed_font
  67.  
  68. # set text_font         "-*-New Century Schoolbook-Medium-R-Normal-*-140-*"
  69. # set edit_font         "-*-Courier-Medium-R-Normal-*-140-*"
  70.  
  71. set subj_group_name ""
  72. set save_name ""
  73. set MustSaveArticle 0
  74. set MustSaveSubjectList 0
  75. set current_subj_index 0
  76. set CurrentGroupIndex 0
  77.  
  78. #-------------
  79. # disp_article
  80. #-------------
  81. proc disp_article {CurrentArticleIndex} {
  82.  
  83.     global skimhome text_font
  84.     global subjlist
  85.     global current_name
  86.     global subject_name
  87.     global current_subj_index
  88.  
  89.     set current_subj_index $CurrentArticleIndex
  90.  
  91.         .r.subj.list selection set $CurrentArticleIndex $CurrentArticleIndex
  92.  
  93.     if [info exists subjlist] {
  94.         set current [lindex $subjlist $CurrentArticleIndex]
  95.         if {$current != ""} {
  96.         .bottomline.b_del configure -state normal
  97.         .bottomline.b_keep configure -state normal
  98.         .bottomline.b_reply configure -state normal
  99.         pack forget .bottomline.save
  100.         .article configure -font $text_font
  101.         .article configure -state normal
  102.         .article delete 0.0 end
  103.  
  104.         if {[file exists $skimhome/Articles/$current]} {
  105.  
  106.             #.article insert 0.0 [read_file $skimhome/Articles/$current ]
  107.             set fd [open $skimhome/Articles/$current]
  108.             .article insert 0.0 [read $fd]
  109.             close $fd
  110.  
  111.             .article configure -state disabled
  112.             set current_name $current
  113.             set subject_name [.r.subj.list get $CurrentArticleIndex]
  114.             if {[file exists $skimhome/Post/$current_name.reply]} {
  115.                 pack .bottomline.replied -side right -padx 20
  116.                 pack .bottomline.del_repl -side right -padx 10
  117.             } else {
  118.                 pack forget .bottomline.replied
  119.                 pack forget .bottomline.del_repl
  120.             }
  121.         } else {
  122.             # The article for this entry in the index is missing.
  123.             # The user must have removed it. Let's rebuild the indexes.
  124.             exec skim indexes
  125.             pack_article 0
  126.         }
  127.         }
  128.     }
  129. }
  130.  
  131. #-------------
  132. # pack_article
  133. #-------------
  134. proc pack_article {GroupIndex} {
  135.  
  136.     global skimhome
  137.  
  138.     .bottomline.b_del configure -state disabled
  139.     .bottomline.b_keep configure -state disabled
  140.     .bottomline.b_reply configure -state disabled
  141.  
  142.     .r.group.list delete 0 end
  143.     set grouplist [exec find $skimhome/Indexes/Articles -type f -printf "%f\n"]
  144.     foreach i [split $grouplist "\n"] {
  145.         .r.group.list insert end $i
  146.     }
  147.  
  148.     pack .bottomline -side bottom -padx 3m -fill x
  149.     place .scroll -in .dummy -relheight 1.0
  150.     place .article -relheight 1.0 -relwidth 0.7 -in .dummy -x 17
  151.     place .r       -relheight 1.0 -relwidth 0.27 -in .dummy -anchor ne -relx 1.0
  152.  
  153.     bind .r.group.list <Button-1> {
  154.             .r.group.list selection set \
  155.         [.r.group.list nearest %y] [.r.group.list nearest %y]
  156.         wm title . "xskim 0.8.4       [.r.group.list get [.r.group.list nearest %y]]"
  157.         getsubjects [.r.group.list nearest %y]
  158.     }
  159.  
  160.         if {$GroupIndex >= [.r.group.list size]} {
  161.             set GroupIndex 0
  162.     }
  163.  
  164.         getsubjects $GroupIndex
  165.     wm title .  "xskim  0.8.4      [.r.group.list get $GroupIndex]"
  166. }
  167.  
  168. #---------------
  169. # unpack_article
  170. #---------------
  171. proc unpack_article {} {
  172.     place forget .r
  173.     place forget .article
  174.     pack forget .bottomline
  175.     place forget .scroll
  176. }
  177.  
  178.  
  179. proc SBDeleteBlock {SB Begin End} {
  180.     global $SB
  181.  
  182.     .l.${SB}.list delete $Begin $End
  183.  
  184.     eval set Value \$$SB
  185.  
  186.     if {$Value != ""} {
  187.     set $SB [eval lreplace \$$SB $Begin $End]
  188.     }
  189. }
  190.  
  191.  
  192. proc SBInsertAtEnd {SB FullSubjectLine} {
  193.     global $SB
  194.  
  195.     .l.${SB}.list insert end [string range $FullSubjectLine 13 end]
  196.  
  197.     lappend $SB "[string range $FullSubjectLine 2 end]"
  198. }
  199.  
  200. proc SBGetWithoutSelectionIndicator {SB Index} {
  201.     global $SB
  202.  
  203.     eval lindex \$$SB $Index
  204. }
  205.  
  206. #--------------
  207. # pack_subjects
  208. #--------------
  209. proc pack_subjects {} {
  210.  
  211.     global skimhome
  212.     global MustSaveSubjectList
  213.  
  214.     .r.group.list delete 0 end
  215.     .r.subj.list delete 0 end
  216.  
  217.     SBDeleteBlock n_selected 0 end
  218.     SBDeleteBlock selected 0 end
  219.  
  220.     set grouplist [exec skim listsubscribednewsgroups]
  221.     foreach i [split $grouplist "\n"] {
  222.         if {[file exists $skimhome/Subjects/$i]} { .r.group.list insert end $i }
  223.     }
  224.     pack forget .r.subj .r.label2
  225.     pack configure .r.group -expand 1
  226.     place .l -relheight 1.0 -relwidth 0.7 -in .dummy 
  227.     place .r -relheight 1.0 -relwidth 0.3 -in .dummy -relx 1.0 -anchor ne
  228.     pack .r.b_get_subj   -side bottom -pady 1m
  229.  
  230.     bind .r.group.list <Button-1> {
  231.         outstanding_work
  232.             .r.group.list selection set \
  233.         [.r.group.list nearest %y] [.r.group.list nearest %y]
  234.         wm title . "xskim  0.8.4      [.r.group.list get [.r.group.list nearest %y]]"
  235.         get_selected %y
  236.     }
  237.  
  238.         .r.group.list selection set 0 0
  239.     get_selected 0
  240.     wm title .  "xskim  0.8.4      [.r.group.list get 0]"
  241. }
  242.  
  243.  
  244. #----------------
  245. # unpack_subjects
  246. #----------------
  247. proc unpack_subjects {} {
  248.     place forget .r
  249.     pack forget .r.b_get_subj
  250.     place forget .l
  251.     pack .r.subj -side bottom  -fill both -expand 1
  252.     pack .r.label2 -side top -fill x
  253. }
  254.  
  255. #-------------------------------------------------
  256. #         procs for article mode
  257. #-------------------------------------------------
  258.  
  259. #------------
  260. # getsubjects
  261. #------------
  262. proc getsubjects {GroupIndex} {
  263.  
  264.     global skimhome
  265.     global subjlist
  266.     global CurrentGroupIndex
  267.  
  268.     set CurrentGroupIndex $GroupIndex
  269.  
  270.     set subjlist [list]
  271.  
  272.     .r.subj.list delete 0 end
  273.     set current [.r.group.list get $GroupIndex]
  274.  
  275.     if {$current != "" && \
  276.         [file exists $skimhome/Indexes/Articles/$current]} {
  277.         set ArticleNumberAndSubjectList [exec cat \
  278.         $skimhome/Indexes/Articles/$current]
  279.     } else {
  280.         set ArticleNumberAndSubjectList ""
  281.     }
  282.  
  283.     foreach i [split $ArticleNumberAndSubjectList "\n"] {
  284.             set IndexOfSeparator [string first " " $i]
  285.             set ArticleNumber [string range $i 0 [expr $IndexOfSeparator - 1]]
  286.             set Subject [string range $i [expr $IndexOfSeparator + 1] end]
  287.  
  288.         lappend subjlist $current.$ArticleNumber
  289.         .r.subj.list insert end $Subject
  290.     }
  291.  
  292.         .r.subj.list selection set 0 0
  293.     disp_article 0
  294. }
  295.  
  296. #------------
  297. # move_article
  298. #------------
  299. proc move_article {Destination} {
  300.  
  301.     global CurrentGroupIndex
  302.     global skimhome
  303.     global current_name
  304.     global subject_name
  305.         global current_subj_index
  306.     global subjlist
  307.  
  308.     if {$Destination == "delete" || $Destination == "keep"} {
  309.         exec skim $Destination $current_name
  310.     } else {
  311.         error "Can't happen"
  312.     }
  313.  
  314.     # Remove the article from the display.
  315.     .article configure -state normal
  316.     .article delete 1.0 end
  317.     .article configure -state disabled
  318.  
  319.     # Remove entry from subject listbox.
  320.     .r.subj.list delete $current_subj_index
  321.  
  322.     # Remove subject from list of subjects.
  323.     set subjlist [lreplace $subjlist $current_subj_index $current_subj_index]
  324.  
  325.     if {[llength $subjlist] > 0} {
  326.         # Display the next article.
  327.         if {$current_subj_index >= [llength $subjlist]} {
  328.             disp_article [expr [llength $subjlist] - 1]
  329.         } else {
  330.         disp_article $current_subj_index
  331.         }
  332.     } else {
  333.         if {$CurrentGroupIndex >= [expr [.r.group.list size] - 1]} {
  334.         if {[expr [.r.group.list size]] > 1} {
  335.             pack_article [expr [.r.group.list size] - 2]
  336.         } else {
  337.             outstanding_work
  338.             unpack_article
  339.             pack_subjects
  340.         }
  341.         } else {
  342.         pack_article $CurrentGroupIndex
  343.         }
  344.     }
  345. }
  346.  
  347. proc skim_cleanup {} {
  348.  
  349.     global skimhome
  350.  
  351.     toplevel .ask
  352.     wm title .ask "Cleanup..."
  353.     wm geometry .ask +100+100
  354.     wm positionfrom .ask user
  355.     frame .ask.top -bd 3 -relief groove
  356.     frame .ask.bottom -bd 1
  357.     pack .ask.top .ask.bottom -side top -fill both
  358.     label .ask.top.l -text \
  359. "Do you really want to remove the files in $skimhome/Skipped, $skimhome/Killed and $skimhome/Deleted?"
  360.     pack .ask.top.l -side left
  361.  
  362.     button .ask.bottom.ok -text "OK" -command {
  363.         destroy .ask
  364.         exec skim cleanup
  365.     }
  366.     button .ask.bottom.cancel -text "Cancel" -command {
  367.         destroy .ask
  368.     }
  369.     pack .ask.bottom.ok .ask.bottom.cancel -side left -padx 1m \
  370.         -pady 1m -expand 1
  371. }
  372.  
  373. #--------------
  374. # skim_articles
  375. #--------------
  376. proc skim_articles {} {
  377.  
  378.     global skimhome
  379.  
  380.     .r.group.list delete 0 end
  381.     set grouplist [exec skim listsubscribednewsgroups]
  382.     foreach i [split $grouplist "\n"] {
  383.         if {[file exists $skimhome/Subjects/$i]} { .r.group.list insert end $i }
  384.     }
  385.     exec skim articles
  386.     pack_article 0
  387. }
  388.  
  389. #------
  390. # reply
  391. #------
  392. proc reply {} {
  393.  
  394.     global skimhome
  395.     global current_name 
  396.     global save_name
  397.     global subject_name
  398.  
  399.     if {[file exists $skimhome/Post/$current_name.reply]} {
  400.         set save_name $skimhome/Post/$current_name.reply
  401.         edit_article $skimhome/Post/$current_name.reply
  402.         return
  403.     }
  404.  
  405.     toplevel .ask
  406.     wm title .ask "Reply to Article..."
  407.     wm geometry .ask +100+100
  408.     wm positionfrom .ask user
  409.     frame .ask.top -bd 3 -relief groove
  410.     frame .ask.bottom -bd 1
  411.     pack .ask.top .ask.bottom -side top -fill both
  412.     label .ask.top.l -text "Do you really want to reply to: $subject_name ?"
  413.     pack .ask.top.l -side left
  414.     
  415.     button .ask.bottom.ok -text "OK" -command {
  416.         destroy .ask
  417.         exec skim replyto $current_name
  418.         set save_name $skimhome/Post/$current_name.reply
  419.         edit_article $skimhome/Post/$current_name.reply
  420.     }
  421.     button .ask.bottom.cancel -text "Cancel" -command {
  422.         destroy .ask
  423.     }
  424.  
  425.     pack .ask.bottom.ok .ask.bottom.cancel -side left -padx 1m -pady 1m \
  426.          -expand 1
  427. }
  428.  
  429. #----------
  430. # edit_article
  431. #----------
  432. proc edit_article {fname} {
  433.     global env
  434.  
  435.     if {![file exists $fname]} {
  436.     error "$fname doesn't exist"
  437.     }
  438.  
  439.     if { [lsearch [array names env] SKIMEDITOR] >= 0 } {
  440.     eval exec $env(SKIMEDITOR) $fname
  441.     } else {
  442.  
  443.     global skimhome textbuf col line goto_command edittab edit_font
  444.     global MustSaveArticle
  445.  
  446.         set trailing_spaces 0
  447.         set col 0
  448.         set line 0
  449.     set textbuf .article
  450.     set goto_command ""
  451.     set edittab 5
  452.     
  453.     pack .bottomline.save -side left -padx 10m
  454.     .bottomline.b_del   configure -state disabled
  455.     .bottomline.b_keep   configure -state disabled
  456.     .bottomline.b_reply configure -state disabled
  457.     
  458.     $textbuf configure -state normal
  459.     $textbuf configure -font $edit_font
  460.     $textbuf delete 0.0 end
  461.     ReadFile $fname
  462.     set MustSaveArticle 1
  463.     GotoXY $textbuf "1.0"
  464.     }
  465. }
  466.  
  467. #-------------
  468. # delete_reply
  469. #-------------
  470. proc delete_reply {} {
  471.  
  472.     global skimhome current_name
  473.     global MustSaveArticle
  474.  
  475.     exec rm $skimhome/Post/$current_name.reply
  476.  
  477.     set MustSaveArticle 0
  478.  
  479.     pack forget .bottomline.replied
  480.     pack forget .bottomline.del_repl
  481.     pack forget .bottomline.save
  482. }
  483.  
  484. #-----------------------------------------------------------
  485. # Comment from the original author of skim.tcl:
  486. # This code I borrowed from XTeXShell by Michael T. Hofmann
  487. #-----------------------------------------------------------
  488. #-----------
  489. # InsertText
  490. #-----------
  491. proc InsertText {textbuf text} {
  492.  
  493. #*** Insert text into editor. Move cursor to end of text
  494.  
  495.         global col line
  496.  
  497.         $textbuf insert $line.$col "$text"
  498.         GotoXY $textbuf [$textbuf index insert]
  499. }
  500.  
  501. proc replicate {string_to_replicate number_of_replications} {
  502.     for {set i 0} {$i < number_of_replications} {incr i} {
  503.     append tmp string_to_replicate
  504.     }
  505.  
  506.     return tmp
  507. }
  508.  
  509. #------------
  510. # InserEditor
  511. #------------
  512. proc InsertEditor {text} {
  513.  
  514. #*** Insert text into editor, but only if editor exists. 
  515. #*** Remove all tabs and replace by spaces. Do not move cursor
  516.  
  517.         global edittab textbuf
  518.         
  519.         set pos [$textbuf index insert]
  520.         InsertText $textbuf "$text" 
  521.  
  522. #*** Now search through text in 512 byte blocks for tabs and replace them
  523. #*** This routine must be very fast !!!!!
  524.  
  525.         if {[string first "\t" $text] >= 0} {
  526.                 for {set sblock 0} {1 < [string length [$textbuf get "0.0 + $sblock c" "0.0 + $sblock c + 2c"]]}\
  527.             {incr sblock 512} {
  528.                         while {1} {
  529.                                 set tpos [string first "\t" [$textbuf get "0.0 + $sblock c" \
  530.                     "0.0 + $sblock c + 512 c"]]
  531.                                 if {$tpos < 0} {break}
  532.  
  533.                                 incr sblock $tpos
  534.                                 $textbuf mark set insert "0.0 + $sblock c"
  535.                                 $textbuf delete insert
  536.  
  537.                                 set col [lindex [split [$textbuf index insert] "."] 1]
  538.                                 $textbuf insert insert [replicate " " [expr \
  539.                     [expr $edittab * ($col / $edittab+ 1)] - $col]]
  540.                         }
  541.                 }
  542.         }
  543.  
  544. #*** Set Cursor position
  545.  
  546.         GotoXY $textbuf $pos
  547. }
  548.  
  549. #-------
  550. # GotoXY
  551. #-------
  552. proc GotoXY {textbuf pos {wcol -1}} {
  553.  
  554. #*** Move Cursor to position pos.
  555. #*** If wcol>=0, goto column wcol. If column wcol does not exist
  556. #*** because the line is shorter, insert spaces at end of line
  557. #*** until wcol is reached. Remove extra spaces when cursor is moved to
  558. #*** the next line.
  559.  
  560.         global col line
  561.         global goto_command
  562.  
  563. #*** Calculate new position
  564.  
  565.         set npos  [$textbuf index "$pos"]
  566.         set nline [lindex [split $npos "."] 0]
  567.         set ncol  [lindex [split $npos "."] 1]
  568.  
  569. #*** Execute goto_command command
  570.  
  571.         eval $goto_command
  572.         set goto_command ""
  573.  
  574. #*** before the line changes, eat up ending spaces (if any)
  575.  
  576.         if {$line != $nline} {
  577.                 EatSpaces $textbuf $line.$col
  578.         }
  579.  
  580. #*** Set Cursor
  581.  
  582.         while {1} {
  583.                 $textbuf insert $npos ""
  584.                 $textbuf mark set insert $npos
  585.  
  586. #*** Get Cursor position
  587.  
  588.                 set col  [lindex [split [$textbuf index insert] "."] 1]
  589.                 set line [lindex [split [$textbuf index insert] "."] 0]
  590.  
  591. #*** If wcol >=0, check if new column=wcol. If not, insert spaces until
  592. #*** column==wcol. This is important for cursor up/down if line length
  593. #*** is smaller than the requested column
  594.  
  595.                 if {$wcol >= 0 && $col < $wcol} {
  596.                         set xpos [$textbuf index "$nline.0 lineend"]
  597.                         $textbuf mark set insert $xpos
  598.  
  599.                         set len [expr $wcol - [lindex [split $xpos "."] 1]]
  600.                         $textbuf insert insert [replicate " " $len]
  601.                         set npos "$nline.$wcol"
  602.                         set wcol -1
  603.                         continue
  604.                 }
  605.  
  606. #*** Redisplay text window if neccessary
  607.  
  608.                 $textbuf yview -pickplace insert
  609.                 focus $textbuf
  610.                 break
  611.         }
  612. }
  613. #---------
  614. #EatSpaces
  615. #---------
  616. proc EatSpaces {textbuf pos} {
  617.  
  618. # Remove trailing spaces from the line.
  619.  
  620.     set line  [$textbuf get "$pos linestart" "$pos lineend"]
  621.     set len   [expr [string length $line] - [string length [string trimright $line]]]
  622.  
  623.     if {$len>0} {
  624.         $textbuf delete "$pos lineend -$len c" "$pos lineend"
  625.     }
  626. }
  627.  
  628. #---------
  629. # ReadFile
  630. #---------
  631. proc ReadFile {fname} {
  632.  
  633. #*** Include a file at current cursor position
  634. #*** if fname == "", then ask for file name
  635.  
  636.         global textbuf
  637.  
  638. #*** Now read file
  639.  
  640.         set fd [open $fname "r"]
  641.         InsertEditor [read $fd]
  642.         close $fd
  643. }
  644.  
  645. #-------------
  646. # InsSelection
  647. #-------------
  648. proc InsSelection {textbuf} {
  649.  
  650.         $textbuf insert insert [selection get]
  651.         GotoXY $textbuf [$textbuf index insert]
  652. }
  653.  
  654.  
  655. #----------
  656. # save_article
  657. #----------
  658. proc save_article {} {
  659.  
  660.     global skimhome
  661.     global current_name save_name
  662.  
  663.     set fd [open $save_name w]
  664.     puts $fd [.article get 0.0 end]
  665.     close $fd
  666.  
  667.     set MustSaveArticle 0
  668.  
  669.     pack forget .bottomline.save
  670.     .article delete 0.0 end
  671.     .article configure -state disabled
  672. }
  673.  
  674. #----------
  675. # make_arti
  676. #----------
  677. proc make_arti {} {
  678.     global skimhome save_name
  679.  
  680.     toplevel .ask
  681.     wm title .ask "Create new Article..."
  682.     wm geometry .ask +100+100
  683.     wm positionfrom .ask user
  684.     frame .ask.top -bd 3 -relief groove
  685.     frame .ask.bottom -bd 1
  686.     pack .ask.top .ask.bottom -side top -fill both
  687.     label .ask.top.l -text "Creating a new Article"
  688.     pack .ask.top.l -side top -anchor nw
  689.  
  690.     frame .ask.top.r
  691.     pack .ask.top.r -side right
  692.     label .ask.top.l_fname    -text "Local filename:"
  693.     entry .ask.top.r.e_fname  -relief sunken
  694.     label .ask.top.l_groups   -text "Newsgroups:"
  695.     entry .ask.top.r.e_groups -relief sunken
  696.     label .ask.top.l_subj     -text "Subject:"
  697.     entry .ask.top.r.e_subj   -relief sunken
  698.     pack .ask.top.l_fname    -side top -anchor ne
  699.     pack .ask.top.r.e_fname  -side top -anchor nw
  700.     pack .ask.top.l_groups   -side top -anchor ne
  701.     pack .ask.top.r.e_groups -side top -anchor nw
  702.     pack .ask.top.l_subj     -side top -anchor ne
  703.     pack .ask.top.r.e_subj   -side top -anchor nw
  704.  
  705.     bind .ask.top.r.e_fname  <Up>     { focus .ask.top.r.e_subj }
  706.     bind .ask.top.r.e_fname  <Down>   { focus .ask.top.r.e_groups }
  707.     bind .ask.top.r.e_fname  <Return> { focus .ask.top.r.e_groups }
  708.     bind .ask.top.r.e_groups <Up>     { focus .ask.top.r.e_fname }
  709.     bind .ask.top.r.e_groups <Down>   { focus .ask.top.r.e_subj }
  710.     bind .ask.top.r.e_groups <Return> { focus .ask.top.r.e_subj }
  711.     bind .ask.top.r.e_subj   <Up>     { focus .ask.top.r.e_groups }
  712.     bind .ask.top.r.e_subj   <Down>   { focus .ask.top.r.e_fname }
  713.     bind .ask.top.r.e_subj   <Return> { .ask.bottom.ok invoke }
  714.     focus .ask.top.r.e_fname
  715.     button .ask.bottom.ok -text "OK" -command {
  716.         set fname [.ask.top.r.e_fname get]
  717.         if {![string length [.ask.top.r.e_fname get]]} { 
  718.             destroy .ask
  719.             return 
  720.         }
  721.         if {![string length [.ask.top.r.e_groups get]]} {
  722.             destroy .ask 
  723.             return 
  724.         }
  725.         if {![string length [.ask.top.r.e_subj get]]} {
  726.             destroy .ask 
  727.             return 
  728.         }
  729.         set save_name $skimhome/Post/$fname
  730.         if {[file exists $skimhome/Post/$fname]} {
  731.                 error "File '$fname' already exists"
  732.         } else {
  733.             exec skim newarticle $fname [.ask.top.r.e_groups get] \
  734.                      [.ask.top.r.e_subj get]
  735.             destroy .ask
  736.             edit_article $save_name
  737.         }
  738.     }
  739.     button .ask.bottom.cancel -text "Cancel" -command {
  740.         destroy .ask
  741.     }
  742.     pack .ask.bottom.ok .ask.bottom.cancel -side left -padx 1m -pady 1m -expand 1
  743. }
  744.  
  745. #----------
  746. # open_post
  747. #----------
  748. proc open_post {} {
  749.  
  750.     global skimhome
  751.     global save_name
  752.     
  753.     toplevel .ask
  754.     wm title .ask "Open Postfile..."
  755.     wm geometry .ask +100+100
  756.     wm positionfrom .ask user
  757.     frame .ask.top -bd 3 -relief groove
  758.     frame .ask.bottom -bd 1
  759.     pack .ask.top -side top -fill both
  760.     label .ask.top.l -text "Select the file you want to edit."
  761.     pack .ask.top.l -side top
  762.  
  763.     frame .ask.file -relief groove -borderwidth 2
  764.     scrollbar .ask.file.scroll \
  765.         -command ".ask.file.outgoing_article_list yview"
  766.  
  767.     listbox .ask.file.outgoing_article_list \
  768.               -yscroll ".ask.file.scroll set" -relief flat \
  769.               -exportselection 1 -width 30 -height 15
  770.  
  771.     pack .ask.file  -side top -fill both -expand 1
  772.     pack .ask.file.scroll -side right -fill y
  773.     pack .ask.file.outgoing_article_list -side left -expand 1 -fill both
  774.     .ask.file.outgoing_article_list delete 0 end
  775.  
  776.     set filelist [exec ls $skimhome/Post]
  777.            foreach i [lsort [split $filelist "\n"]] {
  778.               .ask.file.outgoing_article_list insert end $i
  779.            }
  780.  
  781.     button .ask.bottom.ok -text "Edit" -command {
  782.         if {[.ask.file.outgoing_article_list curselection] != ""} {
  783.         set save_name \
  784.             $skimhome/Post/[.ask.file.outgoing_article_list \
  785.                 get [.ask.file.outgoing_article_list curselection]]
  786.         destroy .ask
  787.         edit_article $save_name
  788.         }
  789.     }
  790.  
  791.     button .ask.bottom.cancel -text "Close" -command {
  792.         destroy .ask
  793.     }
  794.     
  795.     pack .ask.bottom.ok .ask.bottom.cancel -side left -padx 1m -pady 1m -expand 1    
  796.     pack .ask.bottom -side bottom -fill both
  797.  
  798. }
  799.  
  800. #------------
  801. # delete_post
  802. #------------
  803. proc delete_post {} {
  804.  
  805.     global skimhome
  806.     global save_name
  807.     
  808.     toplevel .ask
  809.     wm title .ask "Delete Postfile..."
  810.     wm geometry .ask +100+100
  811.     wm positionfrom .ask user
  812.     frame .ask.top -bd 3 -relief groove
  813.     frame .ask.bottom -bd 1
  814.     pack .ask.top -side top -fill both
  815.     label .ask.top.l -text "Select the file you want to delete."
  816.     pack .ask.top.l -side top
  817.  
  818.     frame .ask.file -relief groove -borderwidth 2
  819.     scrollbar .ask.file.scroll \
  820.         -command ".ask.file.outgoing_article_list yview"
  821.  
  822.     listbox .ask.file.outgoing_article_list   \
  823.         -yscroll ".ask.file.scroll set" \
  824.         -relief flat -exportselection 1 -width 30 -height 15
  825.  
  826.     pack .ask.file  -side top -fill both -expand 1
  827.     pack .ask.file.scroll -side right -fill y
  828.     pack .ask.file.outgoing_article_list   -side left -expand 1 -fill both
  829.  
  830.     .ask.file.outgoing_article_list delete 0 end
  831.     set filelist [exec ls $skimhome/Post]
  832.            foreach i [lsort [split $filelist "\n"]] {
  833.               .ask.file.outgoing_article_list insert end $i
  834.            }
  835.  
  836.     button .ask.bottom.ok -text "Delete" -command {
  837.         if {[.ask.file.outgoing_article_list curselection] != ""} {
  838.         set save_name $skimhome/Post/[.ask.file.outgoing_article_list get \
  839.             [.ask.file.outgoing_article_list curselection]]
  840.         exec rm $save_name
  841.         .ask.file.outgoing_article_list delete 0 end
  842.         set filelist [exec ls $skimhome/Post]
  843.         foreach i [lsort [split $filelist "\n"]] {
  844.             .ask.file.outgoing_article_list insert end $i
  845.             }
  846.         }
  847.     }
  848.  
  849.     button .ask.bottom.cancel -text "Close" -command {
  850.         destroy .ask
  851.     }
  852.     
  853.     pack .ask.bottom.ok .ask.bottom.cancel -side left -padx 1m -pady 1m -expand 1    
  854.     pack .ask.bottom -side bottom -fill both
  855.  
  856. }
  857.  
  858. #------------
  859. # post
  860. #------------
  861. proc post {} {
  862.  
  863.     global skimhome
  864.     global save_name
  865.     
  866.     toplevel .ask
  867.     wm title .ask "Post file..."
  868.     wm geometry .ask +100+100
  869.     wm positionfrom .ask user
  870.     frame .ask.top -bd 3 -relief groove
  871.     frame .ask.bottom -bd 1
  872.     pack .ask.top -side top -fill both
  873.     label .ask.top.l -text "Select the file you want to post."
  874.     pack .ask.top.l -side top
  875.  
  876.     frame .ask.file -relief groove -borderwidth 2
  877.     scrollbar .ask.file.scroll \
  878.         -command ".ask.file.outgoing_article_list yview"
  879.  
  880.     listbox   .ask.file.outgoing_article_list \
  881.         -yscroll ".ask.file.scroll set" \
  882.         -relief flat -width 30 -height 15 -exportselection 1
  883.  
  884.     pack .ask.file  -side top -fill both -expand 1
  885.     pack .ask.file.scroll -side right -fill y
  886.     pack .ask.file.outgoing_article_list   -side left -expand 1 -fill both
  887.     .ask.file.outgoing_article_list delete 0 end
  888.  
  889.     set filelist [exec ls $skimhome/Post]
  890.            foreach i [lsort [split $filelist "\n"]] {
  891.               .ask.file.outgoing_article_list insert end $i
  892.            }
  893.  
  894.     button .ask.bottom.ok -text "Post" -command {
  895.             if {[.ask.file.outgoing_article_list curselection] != ""} {
  896.             exec skim post [.ask.file.outgoing_article_list get \
  897.                 [.ask.file.outgoing_article_list curselection]]
  898.             .ask.file.outgoing_article_list delete 0 end
  899.             set filelist [exec ls $skimhome/Post]
  900.                    foreach i [lsort [split $filelist "\n"]] {
  901.                       .ask.file.outgoing_article_list insert end $i
  902.                    }
  903.         }
  904.     }
  905.  
  906.     button .ask.bottom.cancel -text "Close" -command {
  907.         destroy .ask
  908.     }
  909.     
  910.     pack .ask.bottom.ok .ask.bottom.cancel -side left -padx 1m -pady 1m -expand 1    
  911.     pack .ask.bottom -side bottom -fill both
  912. }
  913.  
  914.  
  915. #-------------------------------------------------
  916. #         procs for subjects mode
  917. #-------------------------------------------------
  918. # get_selected
  919. #-------------
  920. proc get_selected {ypos} {
  921.  
  922.     global skimhome
  923.     global subj_group_name
  924.  
  925.     set current [.r.group.list get [.r.group.list nearest $ypos]]
  926.     if {$current == ""} { return }
  927.     if {![file exists $skimhome/Subjects/$current]} { return }
  928.  
  929.     SBDeleteBlock n_selected 0 end
  930.     SBDeleteBlock selected   0 end
  931.  
  932.     set subjlist [exec cat "$skimhome/Subjects/$current"]
  933.  
  934.     foreach i [split $subjlist "\n"] {
  935.         set SelectionIndicator [string index $i 0]
  936.  
  937.         if {$SelectionIndicator == "+"} {
  938.             SBInsertAtEnd selected $i
  939.         } elseif {$SelectionIndicator == "-"} {
  940.             SBInsertAtEnd n_selected $i
  941.         } else {
  942.         error "Incorrect format: $i"
  943.         }
  944.     }
  945.  
  946.     set subj_group_name $current
  947. }
  948.  
  949. #------------------
  950. # ins_select
  951. #------------------
  952. proc ins_select {} {
  953.  
  954.     global skimhome
  955.     global MustSaveSubjectList
  956.  
  957.     set select_list [.l.n_selected.list curselection]
  958.  
  959.     if {![llength $select_list]} { return }
  960.     set MustSaveSubjectList 1
  961.  
  962.     foreach i $select_list {
  963.         SBInsertAtEnd selected \
  964.             "  [SBGetWithoutSelectionIndicator n_selected $i]"
  965.     }
  966.  
  967.     SBDeleteBlock n_selected [lindex $select_list 0] \
  968.          [lindex $select_list [expr [llength $select_list] - 1]]
  969. }
  970.  
  971. #-------------
  972. # ins_n_select
  973. #-------------
  974. proc ins_n_select {} {
  975.  
  976.     global skimhome
  977.     global MustSaveSubjectList
  978.     
  979.     set select_list [.l.selected.list curselection]
  980.  
  981.     if {![llength $select_list]} { return }
  982.  
  983.     set MustSaveSubjectList 1
  984.  
  985.     foreach i $select_list {
  986.         SBInsertAtEnd n_selected \
  987.             "  [SBGetWithoutSelectionIndicator selected $i]"
  988.     }
  989.  
  990.     SBDeleteBlock selected [lindex $select_list 0] \
  991.         [lindex $select_list [expr [llength $select_list] - 1]]
  992. }
  993.  
  994. proc save_subjlist {} {
  995.  
  996.     global skimhome
  997.     global subj_group_name
  998.     global MustSaveSubjectList
  999.  
  1000.     if {![string compare $subj_group_name ""]} {
  1001.         return
  1002.     }
  1003.  
  1004.     exec rm $skimhome/Subjects/$subj_group_name
  1005.  
  1006.     set fid [open $skimhome/Subjects/$subj_group_name w]
  1007.  
  1008.     for {set i 0} {$i < [.l.selected.list size]} {incr i} {
  1009.         puts $fid "+ [SBGetWithoutSelectionIndicator selected $i]"
  1010.     }
  1011.  
  1012.     for {set i 0} {$i < [.l.n_selected.list size]} {incr i} {
  1013.         puts $fid "- [SBGetWithoutSelectionIndicator n_selected $i]"
  1014.     }
  1015.  
  1016.     flush $fid
  1017.     close $fid
  1018.  
  1019.     set MustSaveSubjectList 0
  1020. }
  1021.  
  1022.  
  1023. proc outstanding_work {} {
  1024.  
  1025.     global MustSaveArticle
  1026.     global MustSaveSubjectList
  1027.  
  1028.     if {$MustSaveSubjectList} {
  1029.         save_subjlist
  1030.     }
  1031.  
  1032.     if {$MustSaveArticle} {
  1033.     save_article
  1034.     }
  1035. }
  1036.  
  1037.  
  1038. #--------------------------------------------------------------------------
  1039. # MAIN
  1040.  
  1041. wm minsize . 640 400
  1042. frame .dummy -width 640 -height 320 -borderwidth 2
  1043.  
  1044. #--------- topline
  1045. frame .topline -relief groove -borderwidth 3
  1046. button .topline.b_subs -text "Skim Subjects" -command { outstanding_work
  1047.                                                    unpack_article
  1048.                            pack_subjects
  1049.                          }
  1050. button .topline.b_arti -text "Skim Articles" -command { outstanding_work
  1051.                                                    unpack_subjects
  1052.                            pack_article 0
  1053.                          }
  1054. button .topline.b_make    -text "New Article"  -command { outstanding_work; .topline.b_arti invoke; make_arti }
  1055. button .topline.b_open    -text "Edit Article" -command { outstanding_work; .topline.b_arti invoke; open_post}
  1056. button .topline.b_delete  -text "Delete Outgoing Article" -command { outstanding_work; delete_post}
  1057. button .topline.b_post    -text "Post"         -command { outstanding_work; post}
  1058. button .topline.b_postall -text "Post All"      -command { outstanding_work; exec skim postall}
  1059. button .topline.b_cleanup -text "Cleanup"      -command { outstanding_work; skim_cleanup}
  1060. button .topline.b_quit    -text "Quit"         -command { outstanding_work; exit }
  1061. pack .topline.b_subs -side left -padx 2m
  1062. pack .topline.b_arti -side left -padx 2m
  1063. pack .topline.b_make -side left -padx 2m
  1064. pack .topline.b_open -side left -padx 2m
  1065. pack .topline.b_delete -side left -padx 2m
  1066. pack .topline.b_post    -side left -padx 2m
  1067. pack .topline.b_postall -side left -padx 2m
  1068. pack .topline.b_cleanup -side left -padx 2m
  1069. pack .topline.b_quit -side right -padx 2m
  1070. pack .topline        -side top -fill x
  1071.  
  1072. #-----------------
  1073. # Articles 
  1074. #-----------------
  1075. frame  .bottomline         -relief groove -borderwidth 2
  1076. button .bottomline.b_del   -text "Delete Article" -activebackground red -state disabled -command {outstanding_work; move_article delete}
  1077. button .bottomline.b_keep   -text "Keep Article" -activebackground green -state disabled -command {outstanding_work; move_article keep}
  1078.  
  1079. button .bottomline.b_reply -text "Reply" -activebackground "light blue" -command {outstanding_work; reply} -state disabled
  1080. button .bottomline.del_repl -text "Delete Reply" -command {outstanding_work; delete_reply}
  1081. button .bottomline.b_new    -text "Get Selected Articles" -command {outstanding_work; skim_articles }
  1082. label  .bottomline.replied -text "Reply exists" -relief sunken
  1083. pack   .bottomline.b_del   -side left -padx 2m
  1084. pack   .bottomline.b_keep   -side left -padx 2m
  1085.  
  1086. pack   .bottomline.b_reply -side left -padx 2m
  1087. pack   .bottomline.b_new  -side right -padx 2m
  1088.  
  1089. scrollbar .scroll -command {.article yview}
  1090. text .article -yscroll ".scroll set" -relief raised -borderwidth 1 -height 40 -width 80 -state disabled\
  1091.     -font $text_font -setgrid 0
  1092.  
  1093. #---------- groups
  1094. frame .r
  1095. frame .r.group -relief groove -borderwidth 2
  1096. label .r.label1 -anchor nw -text "Groups:"
  1097. scrollbar .r.group.scroll -command ".r.group.list yview"
  1098. listbox   .r.group.list   -yscroll ".r.group.scroll set" -relief flat \
  1099.           -width 30 -height 5 -exportselection 1
  1100.  
  1101. pack .r.label1 -side top -fill x
  1102. pack .r.group  -side top -fill both -expand 1
  1103. pack .r.group.scroll -side right -fill y
  1104. pack .r.group.list   -side left -expand 1 -fill both
  1105.  
  1106. #----------
  1107. frame .r.subj    -relief groove -borderwidth 2
  1108. label .r.label2  -anchor nw -text "Subjects:"
  1109. scrollbar .r.subj.scroll -command ".r.subj.list yview"
  1110. listbox   .r.subj.list   -yscroll ".r.subj.scroll set" -relief flat \
  1111.           -width 30 -height 5 -selectmode single
  1112.  
  1113. pack .r.label2 -side top -fill x
  1114. pack .r.subj -side bottom  -fill both -expand 1
  1115. pack .r.subj.scroll -side right -fill y
  1116. pack .r.subj.list   -side left -expand 1 -fill both
  1117.  
  1118. pack .dummy -side top -expand 1 -fill both -padx 2m -pady 1m
  1119.  
  1120. #--------------
  1121. # subjects
  1122. #--------------
  1123.  
  1124. frame .l
  1125. frame .l.selected -relief groove -borderwidth 2
  1126. label .l.label1 -anchor nw -text "Selected Subjects:"
  1127.  
  1128. scrollbar .l.selected.scroll -command ".l.selected.list yview"
  1129.  
  1130. set selected {}
  1131. listbox   .l.selected.list   -yscroll ".l.selected.scroll set" -relief flat \
  1132.             -width 40 -height 5 -exportselection 1 -font $fixed_font \
  1133.         -selectmode extended
  1134.  
  1135. pack .l.label1 -side top -fill x
  1136. pack .l.selected  -side top -fill both -expand 1
  1137. pack .l.selected.scroll -side right -fill y
  1138.  
  1139. pack .l.selected.list   -side left -expand 1 -fill both
  1140.  
  1141. frame .l.n_selected -relief groove -borderwidth 2
  1142. label .l.label2 -anchor nw -text "Not selected Subjects:"
  1143.  
  1144. scrollbar .l.n_selected.scroll -command ".l.n_selected.list yview"
  1145.  
  1146. set n_selected {}
  1147. listbox   .l.n_selected.list   -yscroll ".l.n_selected.scroll set"\
  1148.          -relief flat -exportselection 0 -font $fixed_font \
  1149.          -width 40 -height 5 -selectmode extended
  1150.  
  1151. # Experimental
  1152. bind .l.n_selected.list <Button-3> {ins_select}
  1153. bind .l.selected.list <Button-3> {ins_n_select}
  1154.  
  1155. frame  .l.button_line
  1156. button .l.button_line.sel    -text "Select" -command  { ins_select }
  1157. button .l.button_line.n_sel  -text "Unselect" -command { ins_n_select }
  1158. place  .l.button_line.sel    -rely 0.5 -relx 0.15 -anchor center -relwidth 0.25
  1159. place  .l.button_line.n_sel  -rely 0.5 -relx 0.85 -anchor center -relwidth 0.25
  1160. pack   .l.button_line -side top -fill x -pady 1m -padx 10m -ipady 12
  1161.  
  1162. pack .l.label2 -side top -fill x
  1163. pack .l.n_selected  -side bottom -fill both -expand 1
  1164. pack .l.n_selected.scroll -side right -fill y
  1165.  
  1166. pack .l.n_selected.list   -side left -expand 1 -fill both
  1167.  
  1168. button .r.b_get_subj -text "Get New Subjects" -command {
  1169.     outstanding_work
  1170.     exec skim subjects
  1171.     pack_subjects
  1172. }
  1173.  
  1174.  
  1175. bind .r.subj.list <Button-1>      {
  1176.     .r.subj.list selection set \
  1177.     [.r.subj.list nearest %y] [.r.subj.list nearest %y]
  1178.     disp_article [.r.subj.list nearest %y]
  1179. }
  1180.  
  1181.  
  1182. #--------
  1183. # edit
  1184. #--------
  1185.  
  1186. button .bottomline.save -text "Save" -command {save_article}
  1187. set trailing_spaces 0
  1188. set col 0
  1189. set line 0
  1190. set textbuf .article
  1191. set goto_command ""
  1192. $textbuf configure -state normal
  1193. bind $textbuf <Home>            {GotoXY  $textbuf [$textbuf index "insert linestart"]}
  1194. bind $textbuf <Up>              {GotoXY  $textbuf [$textbuf index insert-1l] $col}
  1195. bind $textbuf <Left>            {GotoXY  $textbuf [$textbuf index insert-1c]}
  1196. bind $textbuf <Right>           {GotoXY  $textbuf [$textbuf index insert+1c]}
  1197. bind $textbuf <Down>            {GotoXY  $textbuf [$textbuf index insert+1l] $col}
  1198. bind $textbuf <End>             {EatSpaces $textbuf $line.$col; GotoXY  $textbuf \
  1199.     [$textbuf index "insert lineend"]}
  1200. bind $textbuf <Prior>           {GotoXY  $textbuf [$textbuf index insert-25l] $col}
  1201. bind $textbuf <Next>            {GotoXY  $textbuf [$textbuf index insert+25l] $col}
  1202. bind $textbuf <Control-Prior>   {GotoXY  $textbuf [$textbuf index insert-100000l] $col}
  1203. bind $textbuf <Control-Next>    {GotoXY  $textbuf [$textbuf index insert+100000l] $col}
  1204. bind $textbuf <Double-2>        {InsSelection %W}
  1205. focus $textbuf
  1206. $textbuf configure -state disabled
  1207.  
  1208. # If there are articles to be read, start with the article screen. Otherwise,
  1209. # start with the subject screen.
  1210. pack_article 0
  1211. if {[.r.group.list size] == 0} {
  1212.     unpack_article
  1213.     pack_subjects
  1214. }
  1215.